import os
import sys

try:
    import nose
    SkipTest = nose.SkipTest
except ImportError:
    nose = None
    class SkipTest(Exception):
        pass


class ConnectionBox(object):
    '''A simple class to make tests over signals.

    Signals should be connected to the *slot* method.
    The user can check if the slot method was called
    by checking the attruibutes *signals_arrived* and
    *signals_args*.
    '''

    def __init__(self):
        self.signals_arrived = 0
        self.signals_args = []

    def slot(self, *args, **kwargs):
        '''A method that should be connected to signals.'''

        self.signals_arrived += 1
        self.signals_args.append((args, kwargs))

    def reset(self):
        '''Resets the ConnectionBox state.'''

        self.signals_arrived = 0
        self.signals_args = []


def with_path(path, root=None, raise_exc=True, stderr=None):
    '''Decorator that raises a `nose.SkipTest` exception if the path
    *path* does not exist.

    The *path* parameter might be an absolute path, a relative path
    or a callable that returns a path.
    If *root* is passed than if *path* is relative it is
    referred to *root*.

    If *raise_exc* is `True`(the default) raises `SkipTest`,
    otherwise prints an error message to *stderr*(default `sys.stderr`).

    If `nose` is avaiable it uses the `nose.SkipTest` exception,
    otherwise it uses a custom `SkipTest`.
    '''
    
    def path_checker_wrapper(func):
        '''Internal wrapper of the *tests.tools.with_path* decorator.'''
        
        def path_checker(*args, **kwargs):
            '''Internal wrapper of the *tests.tools.with_path* decorator.
            
            It checks that the *path* path exists before calling
            the function.
            '''
            
            try:
                path_to_check = path()
            except TypeError:
                path_to_check = path

            if os.path.isabs(path_to_check):
                path_to_check = path_to_check
            elif root is None or os.path.realpath(root) == os.getcwd():
                path_to_check = os.path.realpath(path_to_check)
            else:
                path_to_check = os.path.realpath(os.path.join(root, path_to_check))
            
            if os.path.exists(path_to_check):
                return func(*args, **kwargs)

            if raise_exc:
                raise SkipTest('The path %r does not exists!'
                                         % path_to_check)
            else:
                if stderr is None:
                    stderr_stream = sys.stderr
                else:
                    stderr_stream = stderr

                stderr_stream.write('SkipTest: The path %r does not exists!'
                                                  % path_to_check)
        
        doc = func.__doc__ if func.__doc__ is not None else ''
        path_checker.__doc__ = (doc +
                                '\nFunction decorated by: %r' % path_checker.__name__)
        path_checker.__name__ = func.__name__
        return path_checker
    return path_checker_wrapper
